﻿using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using Microsoft.VisualBasic.Logging;
using Common;
using GlobalParams;
using NewLife.Log;
using Emgu.CV.Reflection;

namespace EmguForm.Core
{
    abstract class ImageProcess
    {
        public ImageProcess() { }

        public Image<Bgr, byte> _image { get; set; }

        private string res;

        public void run()
        {
            Task task = new Task(proccess);
            task.Start();

        }

        abstract public void proccess();





        /// <summary>
        /// 灰度化
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> toGray(Image<Bgr, byte> src, PictureBox contain = null)
        {
            Image<Gray, byte> dst = src.Convert<Gray, byte>();
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        /// <summary>
        /// 二值化
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="threshold"></param>
        /// <param name="maxValue"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> toBin(Image<Gray, byte> src, int threshold, int maxValue, PictureBox contain = null)
        {
            Image<Gray, byte> dst = src.ThresholdBinary(new Gray(threshold), new Gray(maxValue));
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        /// <summary>
        /// 自适应二值化
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="maxValue"></param>
        /// <param name="blockSize"></param>
        /// <param name="param1"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> toBinAdaptive(Image<Gray, byte> src, double maxValue = 100, int blockSize = 3, double param1 = 3, PictureBox contain = null)
        {
            Image<Gray, byte> dst = src.ThresholdAdaptive(new Gray(maxValue), AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, blockSize, new Gray(param1));
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }

        public Image<Gray, byte> toCanny(Image<Gray, byte> src, double thresh, double threshLinking, PictureBox contain = null)
        {
            Image<Gray, byte> dst = src.Canny(thresh, threshLinking);
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        /// <summary>
        /// 中值模糊
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="size"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> smoothMedian(Image<Gray, byte> src, int size = 3, PictureBox contain = null)
        {
            if (size % 2 == 1)
            {
                Image<Gray, byte> dst = src.SmoothMedian(size);
                if (contain != null)
                {
                    contain.Image = dst.ToBitmap();
                }
                return dst;
            }
            return src;
        }
        /// <summary>
        /// 高斯迷糊
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="kernelSize"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> smoothGaussian(Image<Gray, byte> src, int kernelSize = 3, PictureBox contain = null)
        {
            if (kernelSize % 2 == 1)
            {
                Image<Gray, byte> dst = src.SmoothGaussian(kernelSize);
                if (contain != null)
                {
                    contain.Image = dst.ToBitmap();
                }
            }
            return src;
        }
        /// <summary>
        /// 双边滤波
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="kernelSize"></param>
        /// <param name="colorSigma"></param>
        /// <param name="spaceSigma"></param>
        /// <param name="contain"></param>
        public Image<Gray, byte> smoothBilatral(Image<Gray, byte> src, int kernelSize = 3, int colorSigma = 3, int spaceSigma = 3, PictureBox contain = null)
        {
            Image<Gray, byte> dst = src.SmoothBilateral(kernelSize, colorSigma, spaceSigma);

            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        public Image<Gray, byte> findContours(Image<Gray, byte> src, ref VectorOfVectorOfPoint vvp, Filter filter = null, PictureBox contain = null)
        {
            Image<Gray, Byte> dst = new Image<Gray, byte>(src.Width, src.Height, new Gray(0));
            vvp = new VectorOfVectorOfPoint();
            Mat b1 = new Mat();
            CvInvoke.FindContours(src, vvp, b1, RetrType.Ccomp, ChainApproxMethod.ChainApproxNone);

            if (filter != null)
            {
                vvp = filter.contoursFilter(vvp);
                //for(int i = 0; i < vvp.Size; i++)
                //{
                //    RotatedRect rec = CvInvoke.FitEllipse(vvp[i]);
                //    CvInvoke.Polylines(dst, Array.ConvertAll(rec.GetVertices(),Point.Round),true, new MCvScalar(255,255,255));
                //    dst.Draw(new LineSegment2DF(rec.Center, ImageParams.circles[0].Center), new Gray(255), 2);
                //}
            }
            for (int i = 0; i < vvp.Size; i++)
            {
                for (int j = 0; j < vvp[i].Size; j++)
                {
                    dst.Data[vvp[i][j].Y, vvp[i][j].X, 0] = 255;
                }
            }

            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        /// <summary>
        /// 找刻度轮廓,需先确定圆心
        /// </summary>
        /// <param name="src"></param>
        /// <param name="vvp"></param>
        /// <param name="filter"></param>
        /// <param name="contain"></param>
        /// <returns></returns>
        public Image<Bgr, byte> findScaleContours(Image<Gray, byte> src, ref VectorOfVectorOfPoint vvp, Filter filter = null, PictureBox contain = null)
        {
            Image<Bgr, Byte> dst = Images.image.Copy(); //new Image<Bgr, byte>(src.Width, src.Height, new Bgr());
            vvp = new VectorOfVectorOfPoint();
            Mat b1 = new Mat();
            CvInvoke.FindContours(src, vvp, b1, RetrType.Ccomp, ChainApproxMethod.ChainApproxNone);

            if (filter != null)
            {
                vvp = filter.contoursFilter(vvp);

                if (vvp.Size > 0 && ImageParams.circles[0].Center.X != 0)
                {
                    List<PointF> recCenter = new List<PointF>();

                    PointF last = new PointF();
                    //double d = int.MaxValue;
                    for (int i = 0; i < vvp.Size; i++)
                    {
                        RotatedRect rec = CvInvoke.FitEllipse(vvp[i]);
                        if (i >= 1)
                        {
                            RotatedRect lastRec = CvInvoke.FitEllipse(vvp[i - 1]);
                            if (Util.Distance(CvInvoke.FitEllipse(vvp[i - 1]).Center, rec.Center) < 30)
                            {
                                rec = new RotatedRect(Util.AvrPoint(new PointF[] { lastRec.Center, rec.Center }), new SizeF((lastRec.Size.Width + rec.Size.Width) / 2, (lastRec.Size.Height + rec.Size.Height) / 2), (rec.Angle + lastRec.Angle) / 2);
                                lastRec = rec;
                            }
                            //dst.Draw(i.ToString(), Point.Round(rec.GetVertices()[0]), FontFace.HersheyComplex, 1.0, new Bgr(Color.Red));
                            else
                            {

                                CvInvoke.Polylines(dst, Array.ConvertAll(rec.GetVertices(), Point.Round), true, new MCvScalar(255, 255, 255));
                                //dst.Draw(new LineSegment2DF(rec.Center, ImageParams.circles[0].Center), new Bgr(Color.Red), 2);
                                dst.Draw(new CircleF(rec.Center, 2), new Bgr(Color.Red), 5);
                                recCenter.Add(rec.Center);

                                //dst.Draw(i.ToString(), Point.Round(rec.GetVertices()[0]), FontFace.HersheyComplex, 1.0, new Bgr(Color.Red));
                            }
                        }
                        else
                        {

                            CvInvoke.Polylines(dst, Array.ConvertAll(rec.GetVertices(), Point.Round), true, new MCvScalar(255, 255, 255));
                            //dst.Draw(new LineSegment2DF(rec.Center, ImageParams.circles[0].Center), new Bgr(Color.Red), 2);
                            dst.Draw(new CircleF(rec.Center, 2), new Bgr(Color.Red), 5);
                            recCenter.Add(rec.Center);

                            // dst.Draw(i.ToString(), Point.Round(rec.GetVertices()[0]), FontFace.HersheyComplex, 1.0, new Bgr(Color.Red));
                        }
                        dst.Draw(new LineSegment2DF(rec.Center, ImageParams.circles[0].Center), new Bgr(Color.Red), 1);
                    }
                    double[] angle = new double[recCenter.Count];
                    for (int i = 1; i < recCenter.Count; i++)
                    {
                        angle[i - 1] = Math.Round(Util.AngleOfPoint(ImageParams.circles[0].Center, recCenter[i - 1], recCenter[i]), 1);
                    }
                    var lst = from v in angle
                              group v by v into G
                              orderby G.Count() descending
                              select new
                              {
                                  data = G.Key,
                                  count = G.Count()
                              };
                    DataUtil dataUtil = new DataUtil("angle", "n");
                    PointF[] pfs = new PointF[angle.Length];
                    int n = 0;
                    string s = "";
                    //foreach (var v in lst)
                    //{
                    //    pfs[n++] = new PointF((float)v.data, v.count);
                    //    s += v.data + "," + v.count + "\n";
                    //}
                    //saveToFile("轮廓刻度角度数据.csv", s);


                    ////刻度拟合
                    //double ang = lst.First().data;
                    //if (ang > 0)
                    //{
                    //    CircleF c = ImageParams.circles[0];
                    //    for (double i = 0; i < 360; i += ang)
                    //    {
                    //        PointF p1 = new Point((int)(c.Center.X + (c.Radius - 30) * Math.Cos(i)), (int)(c.Center.Y - (c.Radius - 30) * Math.Sin(i)));
                    //        dst.Draw(new LineSegment2DF(p1, p1), new Bgr(Color.Red), 5);

                    //    }
                    //}


                    //CvInvoke.Ellipse(dst, new Point((int)(c.Center.X + c.Radius * Math.Cos(i)), (int)(c.Center.Y - c.Radius * Math.Sin(i))), new Size(1, 3), i, 0, i, new MCvScalar(0, 0, 255), 2, LineType.FourConnected, 0);
                    // Log.error(ang + "");
                    //return  dataUtil.draw(pfs);
                }
            }
            for (int i = 0; i < vvp.Size; i++)
            {
                for (int j = 0; j < vvp[i].Size; j++)
                {
                    dst.Data[vvp[i][j].Y, vvp[i][j].X, 0] = 255;
                }
            }

            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        public Image<Gray, byte> laplace(Image<Gray, byte> src, int apertureSize, PictureBox contain = null)
        {
            XTrace.WriteLine("拉普拉斯变换");
            Image<Gray, byte> dst = src.Laplace(apertureSize).Convert<Gray, byte>();
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        public Image<Gray, byte> sobel(Image<Gray, byte> src, int xorder, int yorder, int apertureSize, PictureBox contain = null)
        {
            XTrace.WriteLine("Sobel变换");
            Image<Gray, byte> dst = src.Sobel(xorder, yorder, apertureSize).Convert<Gray, byte>();
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        /// <summary>
        /// 霍夫圆检测
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="circles"></param>
        /// <param name="cannyThreshold"></param>
        /// <param name="accumulatorThreshold"></param>
        /// <param name="dp"></param>
        /// <param name="minDist"></param>
        /// <param name="minRadius"></param>
        /// <param name="maxRadius"></param>
        /// <param name="circleFilter">过滤器</param>
        /// <param name="contain"></param>
        public Image<Bgr, byte> findCircle(Image<Gray, byte> src, ref CircleF[] circles, int cannyThreshold, int accumulatorThreshold, double dp, double minDist, int minRadius = 0, int maxRadius = 0, Filter circleFilter = null, PictureBox contain = null)
        {
            long start = DateTime.Now.Millisecond;

            circles = src.HoughCircles(new Gray(cannyThreshold), new Gray(accumulatorThreshold), dp, minDist, minRadius, maxRadius)[0];
            long end = DateTime.Now.Millisecond;
            XTrace.WriteLine("Hough圆检测耗时:" + (end - start) + "ms");
            XTrace.WriteLine("共检测到 " + circles.Length + " 个圆");
            if (circleFilter != null)
            {
                XTrace.WriteLine("执行圆过滤器");
                circles = circleFilter.filter(circles);
                XTrace.WriteLine("过滤后还剩 " + circles.Length + " 个圆");
            }
            Image<Bgr, byte> dst = src.Copy().Convert<Bgr, byte>();
            if (circles.Length > 0)
            {
                foreach (CircleF c in circles)
                {
                    dst.Draw(c, new Bgr(Color.Yellow), 5);
                    dst.Draw(new CircleF(c.Center, 2), new Bgr(Color.Yellow), 5);
                    XTrace.WriteLine("圆心:(" + c.Center.X + "," + c.Center.Y + "),半径:" + c.Radius + ",面积:" + c.Area);
                }
            }
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            return dst;
        }
        public Image<Bgr, byte> findCircle(Image<Gray, byte> src, ref CircleF[] circles)
        {
            int[] stepY = new int[8];
            for (int i = 0; i < stepY.Length; i++)
            {
                stepY[i] = (int)Math.Floor((double)(i * src.Height / stepY.Length));
            }
            Image<Bgr, byte> dst = src.Copy().Convert<Bgr, byte>();

            List<Point> list = new List<Point>();
            int lastX = 0;
            for (int x = 0; x < src.Width; x += 2)
            {
                for (int i = 0; i < stepY.Length; i++)
                {
                    if (src[stepY[i], x].Intensity == 255)
                    {
                        Point p = new Point(x, stepY[i]);
                        list.Add(p);
                        dst.Draw(new CircleF(p, 1), new Bgr(Color.Red), 5);
                    }
                }
            }
            list.Sort((a, b) => a.X - b.X);
            PointF lastCenter = new Point();
            int count = 0;
            for (int i = 0; i < list.Count - 3; i++)
            {
                //取三个点
                Point p1 = list[i];
                Point p2 = list[i + 1];
                Point p3 = list[i + 2];
                if (Util.Distance(p1, p2) < 15 ||
                    Util.Distance(p1, p3) < 15 ||
                    Util.Distance(p2, p3) < 15)
                    continue;
                CircleF c = circle(p1, p2, p3);
                if (c.Radius > 50 && c.Radius < Math.Min(src.Width / 2, src.Height / 2))
                {
                    //在剩下的里边取个点
                    int n = 0;
                    for (int j = i + 3; j < list.Count; j++)
                    {
                        Point p = list[j];
                        double d = Util.Distance(p, c.Center);
                        double r = c.Radius;
                        if (d > r - 20 && d < r + 20)
                        {
                            n++;
                            dst.Draw(new CircleF(p, 1), new Bgr(Color.Blue), 5);
                            dst.Draw(new LineSegment2D(p, Point.Round(c.Center)), new Bgr(Color.Blue), 1);
                        }
                    }
                    if (n >= 3 && n < 10 && Util.Distance(lastCenter, c.Center) > 10)// && c.Center.X < p3.X
                    {
                        dst.Draw(circle(p1, p2, p3), new Bgr(Color.Green), 2);
                        dst.Draw(new CircleF(p1, 1), new Bgr(Color.Yellow), 5);
                        dst.Draw(new CircleF(p2, 1), new Bgr(Color.Yellow), 5);
                        dst.Draw(new CircleF(p3, 1), new Bgr(Color.Yellow), 5);
                    }
                    lastCenter = c.Center;
                    //count++;
                    //dst.Draw(new CircleF(p1, 1), new Bgr(Color.Yellow), 5);
                    //dst.Draw(new CircleF(p2, 1), new Bgr(Color.Yellow), 5);
                    //dst.Draw(new CircleF(p3, 1), new Bgr(Color.Yellow), 5);
                    //dst.Draw(circle(p1, p2, p3), new Bgr(Color.Green), 2);
                    //if (count>=2)
                    //break;

                }
            }
            return dst;
        }
        public Image<Bgr, byte> findCircle2(Image<Gray, byte> src, ref CircleF[] circles)
        {
            //src.SmoothGaussian(37);
            Image<Bgr, byte> dst = src.Copy().Convert<Bgr, byte>();

            int[] stepY = new int[9];
            for (int i = 0; i < stepY.Length; i++)
            {
                stepY[i] = (int)Math.Floor((double)(i * src.Height / stepY.Length));
                dst.Draw(new LineSegment2D(new Point(0, stepY[i]), new Point(src.Width, stepY[i])), new Bgr(Color.Orange), 1);
            }
            int[] stepX = new int[9];
            for (int i = 0; i < stepX.Length; i++)
            {
                stepX[i] = (int)Math.Floor((double)(i * src.Width / stepX.Length));
                dst.Draw(new LineSegment2D(new Point(stepX[i], 0), new Point(stepX[i], src.Height)), new Bgr(Color.Orange), 1);
            }
            Point lastPoint = new Point();
            List<Point> list = new List<Point>();
            for (int x = 0; x < src.Width; x += 2)
            {
                for (int i = 0; i < stepY.Length; i++)
                {
                    if (src[stepY[i], x].Intensity == 255)
                    {
                        Point p = new Point(x, stepY[i]);
                        if (Util.Distance(lastPoint, p) > 30)//过滤相近的点
                        {
                            list.Add(p);
                            dst.Draw(new CircleF(p, 1), new Bgr(Color.Red), 5);
                        }
                        lastPoint = p;
                    }
                }
            }
            List<Point> list2 = new List<Point>();
            for (int y = 0; y < src.Height; y += 2)
            {
                for (int i = 0; i < stepX.Length; i++)
                {
                    if (src[y, stepX[i]].Intensity == 255)
                    {
                        Point p = new Point(stepX[i], y);
                        if (Util.Distance(lastPoint, p) > 30)//过滤相近的点
                        {
                            list2.Add(p);
                            dst.Draw(new CircleF(p, 1), new Bgr(Color.Red), 5);
                        }
                        lastPoint = p;
                    }
                }
            }
            list2.Sort((a, b) => a.Y - b.Y);
            list.Sort((a, b) => a.X - b.X);
            list.AddRange(list2);
            PointF lastCenter = new Point();
            int count = 0;
            List<CircleF> circleList = new List<CircleF>();
            List<PointF> centerList = new List<PointF>();

            for (int i = 0; i < list.Count - 2; i++)
            {
                //取2个点
                Point p1 = list[i];
                Point p2 = list[i + 1];
                //在剩下的里边取一个点组圆
                for (int j = i + 2; j < list.Count; j++)
                {
                    Point p = list[j];
                    CircleF c = circle(p1, p2, p);
                    //记下圆
                    if (c.Center.X > 0 && c.Center.X < src.Width && c.Center.Y > 0 && c.Center.Y < src.Height && c.Radius <= Math.Min(src.Width / 2, src.Height / 2)
                        && Util.Distance(lastCenter, c.Center) > 10)
                    {
                        circleList.Add(c);
                        centerList.Add(c.Center);
                        //dst.Draw(new CircleF(p, 1), new Bgr(Color.Blue), 5);
                        //dst.Draw(new LineSegment2D(p, Point.Round(c.Center)), new Bgr(Color.Blue), 1);
                        dst.Draw(new CircleF(c.Center, 1), new Bgr(Color.Blue), 5);

                    }
                    lastCenter = c.Center;
                }
            }
            var result = from item in centerList   //每一项                          
                         group item by item into gro   //按项分组，没组就是gro                          
                         orderby gro.Count() descending   //按照每组的数量进行排序                          
                         select new { circle = gro.Key, count = gro.Count() };
            foreach (var item in result.Take(1))
            {
                //dst.Draw(item.circle, new Bgr(Color.Red), 5);
            }
            //找圆心最多的区域//TODO这个算法有问题 需改进
            CircleF cc = new CircleF();
            List<CircleF> ccList = new List<CircleF>();
            int max = 0;
            foreach (CircleF pf1 in circleList)
            {
                int n = 0;
                // new List<CircleF>();

                foreach (CircleF pf2 in circleList)
                {
                    if (Util.Distance(pf1.Center, pf2.Center) < stepY.Length / 2)
                    {
                        n++;
                    }
                }
                // Log.error("n=" + n);

                if (n > max)
                {
                    cc = pf1;
                    max = n;
                    ccList.Add(cc);
                }
            }
            //优化：固定范围 不用每次获取只
            //循环次数多的放最外边
            //for (int x = 10,w=src.Width; x < w; x++)
            //{
            //    for (int y = 10,h=src.Height; y < h; y++)
            //    {
            //        int n = 0;
            //        foreach (CircleF c in circleList)
            //        {
            //            if (Util.Distance(c.Center, new Point(x, y)) < 10)
            //            {
            //                n++;
            //            }
            //        }
            //        if (n > max)
            //        {
            //            cc = new CircleF(new PointF(x, y), 5);
            //            dst.Draw(cc, new Bgr(Color.Yellow), 3);
            //            max = n;
            //            ccList.Add(cc);
            //        }
            //    }

            //}
            foreach (CircleF c in ccList)
            {
                dst.Draw(c, new Bgr(Color.White), 3);
                dst.Draw(new CircleF(c.Center, 2), new Bgr(Color.White), 2);
            }
            dst.Draw(cc, new Bgr(Color.Yellow), 3);
            dst.Draw(new CircleF(cc.Center, 2), new Bgr(Color.Yellow), 5);
            //dst = drawData(centerList.ToArray(), "", "", (int)(src.Width*1.5), (int)(src.Height*2),true);
            XTrace.WriteLine("max=" + max);

            return dst;
        }

        public Image<Bgr, byte> findCircle3(Image<Gray, byte> src, VectorOfVectorOfPoint vvp, ref CircleF[] circles)
        {
            XTrace.WriteLine("随机抽样圆检测");
            Image<Bgr, byte> dst = src.Copy().Convert<Bgr, byte>();

            long start = DateTime.Now.Millisecond;
            double minSd = 10000.0;
            int minSdContours = 0;
            Random random = new Random(Guid.NewGuid().GetHashCode());
            List<CircleF> ccList = new List<CircleF>();
            for (int i = 0; i < vvp.Size; i++)
            {
                if (vvp[i].Size < 50)//TODO轮廓长度根据什么来过滤?
                    continue;
                List<PointF> list = new List<PointF>();
                //TODO优化:定义伪随机序列,保证一张图每次检测到的圆位置相同
                for (int j = 0; j < vvp[i].Size; j++)
                {
                    int ran1 = 0;
                    int ran2 = 0;
                    int ran3 = 0;
                    while (ran1 == ran2 || ran1 == ran3 || ran2 == ran3 /*|| Math.Abs(ran1-ran2)< vvp[i].Size/10 || Math.Abs(ran1 - ran3) < vvp[i].Size /10 || Math.Abs(ran2 - ran3) < vvp[i].Size/10*/)
                    {
                        ran1 = random.Next(0, vvp[i].Size - 1);
                        ran2 = random.Next(0, vvp[i].Size - 1);
                        ran3 = random.Next(0, vvp[i].Size - 1);
                    }
                    Point p1 = vvp[i][ran1];
                    Point p2 = vvp[i][ran2];
                    Point p3 = vvp[i][ran3];

                    CircleF c = circle(p1, p2, p3);
                    if (c.Radius > ImageParams.circle_min_r && c.Radius < Math.Min(src.Width, src.Height) && !isBoundaryPoint(p1, src) && !isBoundaryPoint(p2, src) && !isBoundaryPoint(p3, src))
                    {
                        list.Add(c.Center);
                        //dst.Draw(c, new Bgr(Color.Yellow), 2);
                        //dst.Draw(new LineSegment2DF(c.Center, p1), new Bgr(Color.Blue), 1);
                        //dst.Draw(new LineSegment2DF(c.Center, p2), new Bgr(Color.Blue), 1);
                        //dst.Draw(new LineSegment2DF(c.Center, p3), new Bgr(Color.Blue), 1);
                        //dst.Draw(new CircleF(c.Center, 2), new Bgr(Color.Red), 1);
                        //dst.Draw(new CircleF(p1, 2), new Bgr(Color.Green), 2);
                        //dst.Draw(new CircleF(p2, 2), new Bgr(Color.Green), 2);
                        //dst.Draw(new CircleF(p3, 2), new Bgr(Color.Green), 2);
                        ccList.Add(c);
                    }
                }
                //计算标准差
                float sumX = 0;
                float sumY = 0;
                foreach (PointF f in list)
                {
                    sumX += f.X;
                    sumY += f.Y;
                }
                float avgX = sumX / list.Count;//平均值
                float avgY = sumY / list.Count;//平均值
                float varianceX = 0;//方差
                float varianceY = 0;//方差
                foreach (PointF f in list)
                {
                    varianceX += (f.X - avgX) * (f.X - avgX);
                    varianceY += (f.Y - avgY) * (f.Y - avgY);
                }
                double sdX = Math.Sqrt(varianceX / list.Count);//标准差
                double sdY = Math.Sqrt(varianceY / list.Count);//标准差
                double sd = Math.Sqrt(sdX * sdX + sdY * sdY);
                //Log.info("轮廓:" + i + "的标准差" + sd + "");
                if (sd < minSd)
                {
                    minSd = sd;
                    minSdContours = i;
                }
            }
            long end = DateTime.Now.Millisecond;
            XTrace.WriteLine("随机抽样圆检测耗时:" + (end - start) + "ms");

            // new Image<Bgr, byte>(src.Size).Convert<Bgr,byte>();
            //一般情况max:areaRadius=5:1较好
            int areaRadius = 15;
            int max = 30;
            CircleF finalCircle = findMostPossibleCenter(ccList, areaRadius, max);
            circles = new CircleF[1];
            circles[0] = finalCircle;
            XTrace.WriteLine("随机抽样圆检圆心:(" + finalCircle.Center.X + "," + finalCircle.Center.Y + ")");
            ////如果标记了起始刻度和终止刻度则绘制刻度圆弧，否则绘制整个圆
            //if(ImageParams.pointStart.X!=0&& ImageParams.pointStart.Y != 0 && ImageParams.pointEnd.X != 0 && ImageParams.pointEnd.Y != 0)
            //{
            //    //计算起始点和终止点与圆心与水平方向的角度
            //    double ang1 = Math.Atan2(ImageParams.pointStart.Y-finalCircle.Center.Y, ImageParams.pointStart.X - finalCircle.Center.X) * 180 / Math.PI;// Util.AngleOfPoint(finalCircle.Center, ImageParams.pointStart, new PointF(finalCircle.Center.X+100, finalCircle.Center.Y));
            //    double ang2 = Math.Atan2(ImageParams.pointEnd.Y - finalCircle.Center.Y, ImageParams.pointEnd.X - finalCircle.Center.X) * 180 / Math.PI;
            //    //半径与圆的交点
            //    PointF p1 = new PointF((float)(finalCircle.Center.X+ finalCircle.Radius*Math.Cos(Math.PI*ang1/180)), (float)(finalCircle.Center.Y + finalCircle.Radius * Math.Sin(Math.PI * ang1 / 180)));
            //    PointF p2 = new PointF((float)(finalCircle.Center.X+ finalCircle.Radius*Math.Cos(Math.PI*ang2/180)), (float)(finalCircle.Center.Y + finalCircle.Radius * Math.Sin(Math.PI * ang2 / 180)));
            //    dst.Draw(new LineSegment2DF(finalCircle.Center,p1),new Bgr(Color.Red),3);
            //    dst.Draw(new LineSegment2DF(finalCircle.Center, p2), new Bgr(Color.Red), 3);

            //    Log.error(ang1+","+ang2);
            //    CvInvoke.Ellipse(dst, Point.Round(finalCircle.Center), new Size((int)finalCircle.Radius, (int)finalCircle.Radius), 0, ang1, 360+ang2, new MCvScalar(0, 0, 255), 3, LineType.Filled, 0);
            //    XTrace.WriteLine(ang1+","+ang2);
            //}
            //else
            //{
            //}
            dst.Draw(finalCircle, new Bgr(Color.Red), 3);
            dst.Draw(new CircleF(finalCircle.Center, 2), new Bgr(Color.Red), 5);
            List<PointF> centerList = new List<PointF>();
            foreach (CircleF c in ccList)
            {
                centerList.Add(c.Center);
            }
            DataUtil dataUtil = new DataUtil("a", "b", (int)(src.Width * 1.5), (int)(src.Height * 1.5));
            //dataUtil.showConcentratedArea = true;
            dataUtil.maxConcentratedNum = max;
            dataUtil.concentratedAreaRadius = areaRadius;
            //dst = dataUtil.draw(centerList.ToArray());
            return dst;
        }
        //圆弧圆检测
        public Image<Bgr, byte> findCircle4(Image<Gray, byte> src, VectorOfVectorOfPoint vvp, ref CircleF[] circles)
        {
            XTrace.WriteLine("圆弧圆检测");
            Image<Bgr, byte> dst = src.Copy().Convert<Bgr, byte>();

            long start = DateTime.Now.Millisecond;
            double minSd = 10000.0;
            int minSdContours = 0;
            Random random = new Random(Guid.NewGuid().GetHashCode());
            List<CircleF> ccList = new List<CircleF>();
            for (int i = 0; i < vvp.Size; i++)
            {
                if (vvp[i].Size < 50)//TODO轮廓长度根据什么来过滤?
                    continue;
                List<PointF> list = new List<PointF>();
                //TODO优化:定义伪随机序列,保证一张图每次检测到的圆位置相同
                for (int j = 0; j < vvp[i].Size; j++)
                {
                    int ran1 = 0;
                    int ran2 = 0;
                    int ran3 = 0;
                    while (ran1 == ran2 || ran1 == ran3 || ran2 == ran3 /*|| Math.Abs(ran1-ran2)< vvp[i].Size/10 || Math.Abs(ran1 - ran3) < vvp[i].Size /10 || Math.Abs(ran2 - ran3) < vvp[i].Size/10*/)
                    {
                        ran1 = random.Next(0, vvp[i].Size - 1);
                        ran2 = random.Next(0, vvp[i].Size - 1);
                        ran3 = random.Next(0, vvp[i].Size - 1);
                    }
                    Point p1 = vvp[i][ran1];
                    Point p2 = vvp[i][ran2];
                    Point p3 = vvp[i][ran3];

                    CircleF c = circle(p1, p2, p3);
                    //预估半径(作为可调节参数)
                    if (c.Radius > ImageParams.circle_min_r && c.Radius < Math.Min(src.Width, src.Height) && !isBoundaryPoint(p1, src) && !isBoundaryPoint(p2, src) && !isBoundaryPoint(p3, src))
                    {
                        list.Add(c.Center);
                        //dst.Draw(c, new Bgr(Color.Yellow), 2);
                        //dst.Draw(new LineSegment2DF(c.Center, p1), new Bgr(Color.Blue), 1);
                        //dst.Draw(new LineSegment2DF(c.Center, p2), new Bgr(Color.Blue), 1);
                        //dst.Draw(new LineSegment2DF(c.Center, p3), new Bgr(Color.Blue), 1);
                        dst.Draw(new CircleF(c.Center, 2), new Bgr(Color.Red), 1);
                        //dst.Draw(new CircleF(p1, 2), new Bgr(Color.Green), 2);
                        //dst.Draw(new CircleF(p2, 2), new Bgr(Color.Green), 2);
                        //dst.Draw(new CircleF(p3, 2), new Bgr(Color.Green), 2);
                        ccList.Add(c);
                    }
                }
                //计算标准差
                float sumX = 0;
                float sumY = 0;
                foreach (PointF f in list)
                {
                    sumX += f.X;
                    sumY += f.Y;
                }
                float avgX = sumX / list.Count;//平均值
                float avgY = sumY / list.Count;//平均值
                float varianceX = 0;//方差
                float varianceY = 0;//方差
                foreach (PointF f in list)
                {
                    varianceX += (f.X - avgX) * (f.X - avgX);
                    varianceY += (f.Y - avgY) * (f.Y - avgY);
                }
                double sdX = Math.Sqrt(varianceX / list.Count);//标准差
                double sdY = Math.Sqrt(varianceY / list.Count);//标准差
                double sd = Math.Sqrt(sdX * sdX + sdY * sdY);
                //Log.info("轮廓:" + i + "的标准差" + sd + "");
                if (sd < minSd)
                {
                    minSd = sd;
                    minSdContours = i;
                }
            }
            long end = DateTime.Now.Millisecond;
            //Log.info("圆弧圆检测耗时:" + (end - start) + "ms");

            // new Image<Bgr, byte>(src.Size).Convert<Bgr,byte>();
            //一般情况max:areaRadius=5:1较好
            int areaRadius = 15;
            int max = 30;
            CircleF finalCircle = findMostPossibleCenter(ccList, areaRadius, max);
            circles = new CircleF[1];
            circles[0] = finalCircle;
            XTrace.WriteLine("圆弧圆检测检圆心:(" + finalCircle.Center.X + "," + finalCircle.Center.Y + ")");
            dst.Draw(finalCircle, new Bgr(Color.Red), 2);
            dst.Draw(new CircleF(finalCircle.Center, 2), new Bgr(Color.Red), 5);
            //List<PointF> centerList = new List<PointF>();
            //foreach (CircleF c in ccList)
            //{
            //    centerList.Add(c.Center);
            //}
            //DataUtil dataUtil = new DataUtil("a", "b", (int)(src.Width * 1.5), (int)(src.Height * 1.5));
            //dataUtil.showConcentratedArea = true;
            //dataUtil.maxConcentratedNum = max;
            //dataUtil.concentratedAreaRadius = areaRadius;
            //dst = dataUtil.draw(centerList.ToArray());
            return dst;
        }
        /// <summary>hhh
        /// 寻找最可能圆
        /// </summary>
        /// <param name="circleList"></param>
        /// <param name="areaRadius"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public CircleF findMostPossibleCenter(List<CircleF> circleList, int areaRadius, int max)
        {
            PointF center = new PointF();
            foreach (CircleF pf1 in circleList)
            {
                int n = 0;
                foreach (CircleF pf2 in circleList)
                {
                    if (Util.Distance(pf1.Center, pf2.Center) < areaRadius)
                    {
                        n++;
                    }
                }
                if (n > max)
                {
                    center = pf1.Center;
                    max = n;
                }
            }

            float rSum = 0;
            int num = 0;
            foreach (CircleF c in circleList)
            {
                if (Util.Distance(center, c.Center) < areaRadius)
                {
                    rSum += c.Radius;
                    num++;
                }
            }
            float r = rSum / num;
            if (num == 0)
            {
                r = 0;
            }

            CircleF circle = new CircleF(center, r);
            return circle;
        }
        /// <summary>
        /// 判断是否是图像的边界上的点
        /// </summary>
        /// <param name="p"></param>
        /// <param name="image"></param>
        /// <returns></returns>
        public bool isBoundaryPoint(Point p, IInputArray image)
        {
            return p.X == 0 || p.Y == 0 || p.X >= image.GetInputArray().GetSize().Width - 1 || p.Y >= image.GetInputArray().GetSize().Height - 1;
        }

        //细化算法
        public Image<Gray, byte> skelatanize(Bitmap image)
        {
            Image<Gray, byte> imgOld = new Image<Gray, byte>(image.ToMat()); // 阳光-未确定
            Image<Gray, byte> img2 = (new Image<Gray, byte>(imgOld.Width, imgOld.Height, new Gray(255))).Sub(imgOld);
            Image<Gray, byte> eroded = new Image<Gray, byte>(img2.Size);
            Image<Gray, byte> temp = new Image<Gray, byte>(img2.Size);
            Image<Gray, byte> skel = new Image<Gray, byte>(img2.Size);
            skel.SetValue(0);
            CvInvoke.Threshold(img2, img2, 127, 255, 0);
            var element = CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), new Point(-1, -1));
            bool done = false;

            while (!done)
            {
                CvInvoke.Erode(img2, eroded, element, new Point(-1, -1), 1, BorderType.Reflect, default(MCvScalar));
                CvInvoke.Dilate(eroded, temp, element, new Point(-1, -1), 1, BorderType.Reflect, default(MCvScalar));
                CvInvoke.Subtract(img2, temp, temp);
                CvInvoke.BitwiseOr(skel, temp, skel);
                eroded.CopyTo(img2);
                if (CvInvoke.CountNonZero(img2) == 0) done = true;
            }
            // Image<Bgr, Byte> img = new Image<Bgr, Byte>(bmp); //where bmp is a Bitmap
            return skel;
        }



        public CircleF circle(Point pt1, Point pt2, Point pt3)
        {
            double x1 = pt1.X, x2 = pt2.X, x3 = pt3.X;
            double y1 = pt1.Y, y2 = pt2.Y, y3 = pt3.Y;
            double a = x1 - x2;
            double b = y1 - y2;
            double c = x1 - x3;
            double d = y1 - y3;
            double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2.0;
            double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2.0;
            double det = b * c - a * d;
            double radius;
            if (Math.Abs(det) < 1e-5)
            {
                radius = 0;
                return new CircleF(new PointF(0, 0), 0);
            }

            double x0 = -(d * e - b * f) / det;
            double y0 = -(a * f - c * e) / det;
            radius = Math.Sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
            return new CircleF(new PointF((float)x0, (float)y0), (float)radius);
        }
        //public CircleF circle2(Point p1, Point p2, Point p3)
        //{
        //    double u = (p2.Y - p1.Y) / (p2.X - p1.X);
        //    double v = (p3.Y - p2.Y) / (p3.X - p2.X);
        //    double w = 0.5 * (p1.Y + p2.Y) + 0.5 * (p1.X + p2.X) / ((p2.Y - p1.Y) / (p2.X - p1.X));
        //    double k = 0.5 * (p2.Y + p3.Y) + 0.5 * (p2.X + p3.X) / ((p3.Y - p2.Y) / (p3.X - p2.X));

        //    double cx = (k - w) / (1 / v - 1 / u);
        //    double cy = (w - k) / u / (1 / v - 1 / u) + w;
        //    double r = Math.Sqrt(Math.Pow((p1.Y - cy), 2) + Math.Pow((p1.X - cx), 2));

        //    return new CircleF(new PointF((float)cx,(float) cy), (float)r);
        //}
        public Image<Bgr, byte> lineByHough(Image<Gray, byte> src, ref LineSegment2D[] lines, double rhoResolution = 1, double thetaResolution = Math.PI / 45.0, int threshold = 20, double minLineWidth = 30, double gapBetweenLines = 10, Filter lineFilter = null, PictureBox contain = null)
        {
            XTrace.WriteLine("Hough直线检测法定位指针");
            long start = DateTime.Now.Millisecond;
            lines = src.HoughLinesBinary(rhoResolution, thetaResolution, threshold, minLineWidth, gapBetweenLines)[0];
            XTrace.WriteLine("共检测到 " + lines.Length + " 条直线");
            if (lineFilter != null)
            {
                XTrace.WriteLine("执行线段滤器");
                lines = lineFilter.lineFilter(lines);
                XTrace.WriteLine("过滤后还剩 " + lines.Length + " 条线段");
            }


            Image<Bgr, byte> dst = _image.Copy();
            foreach (LineSegment2D line in lines)
            {
                dst.Draw(line, new Bgr(Color.Red), 2);
            }
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            long end = DateTime.Now.Millisecond;
            XTrace.WriteLine("耗时:" + (end - start) + "ms"); ;
            return dst;
        }
        public Image<Bgr, byte> lineByRGS(Image<Gray, byte> src, CircleF circle, ref LineSegment2D[] lines, PictureBox contain = null)
        {
            XTrace.WriteLine("径向灰度求和法定位指针");
            long start = DateTime.Now.Millisecond;
            double a = circle.Center.X;
            double b = circle.Center.Y;
            double r = circle.Radius;
            double min = double.MaxValue;
            double max = 0;
            int angle = 0;
            Image<Bgr, byte> dst = _image.Copy();
            //注释掉
            //string str = "";
            List<Point> list = new List<Point>();
            for (int deg = 0; deg < 360; deg++)//360可调节
            {
                //转弧度
                double radian = deg * Math.PI / 180;
                double s = 0;
                for (int i = 0; i < r; i++)
                {
                    int x = (int)(a + i * Math.Cos(radian));
                    int y = (int)(b - i * Math.Sin(radian));
                    x = x <= 0 ? 0 : x;
                    y = y <= 0 ? 0 : y;
                    x = x >= src.Width ? src.Width - 1 : x;
                    y = y >= src.Height ? src.Height - 1 : y;
                    s += src[y, x].Intensity;
                }
                //注释掉
                //str += deg+ ","+s+"\n";
                if (s > max)
                {
                    max = s;
                }
                if (s < min)
                {
                    angle = deg;
                    min = s;
                }
                Point temp = new Point(deg, (int)s);
                list.Add(temp);
            }
            XTrace.WriteLine("指针角度:" + angle);

            int x0 = (int)(a + r * Math.Cos(angle * Math.PI / 180));
            int y0 = (int)(b - r * Math.Sin(angle * Math.PI / 180));
            Point p = new Point(x0, y0);
            Point center = Point.Round(circle.Center);
            long end = DateTime.Now.Millisecond;
            XTrace.WriteLine("耗时:" + (end - start) + "ms");
            lines = new LineSegment2D[1];
            lines[0] = new LineSegment2D(center, p);
            dst.Draw(new LineSegment2D(p, center), new Bgr(Color.Red), 2);
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }

            //注释掉
            //saveToFile( "径向直线检测数据.csv", str);
            return dst;// drawData(list.ToArray(), "angle", "sum(gray)", 360, (int)max,true) ;
        }
        //环向快速模板匹配检测指针
        public Image<Bgr, byte> lineByCTM(Image<Gray, byte> src, CircleF circle, ref LineSegment2D[] lines, PictureBox contain = null)
        {
            long start = DateTime.Now.Millisecond;
            double a = circle.Center.X;
            double b = circle.Center.Y;
            double r = circle.Radius;
            Image<Bgr, byte> dst = src.Convert<Bgr, byte>().Copy();
            //注意这里只有确定了模板终点才进行模相似度计算，否则直接返回
            //待改进的：这里是使用了终点到圆心的这段模板来做的相似度计算，实际应该为起始点到终点的模板，但这种计算比较复杂
            if (/*ImageParams.pointerStart.X!=0&& ImageParams.pointerStart.Y != 0&&*/ ImageParams.pointerEnd.X == 0 || ImageParams.pointerEnd.Y == 0)
            {
                return dst;
            }
            //计算指针模板像素
            double[] template = ImageParams.templateGray;
            double templateAngle = Math.Atan2(b - ImageParams.pointerEnd.Y, a - ImageParams.pointerEnd.X);
            if (template == null)
            {
                template = new double[(int)(Util.Distance(circle.Center, ImageParams.pointerEnd))];

                for (int i = 0; i < template.Length; i++)
                {
                    int x = (int)(a - i * Math.Cos(templateAngle));
                    int y = (int)(b - i * Math.Sin(templateAngle));
                    x = x <= 0 ? 0 : x;
                    y = y <= 0 ? 0 : y;
                    x = x >= src.Width ? src.Width - 1 : x;
                    y = y >= src.Height ? src.Height - 1 : y;

                    if (ImageParams.ctmModel == ImageParams.CTM_MODEL.POINT)
                    {
                        template[i] = src[y, x].Intensity;
                    }
                    else if (ImageParams.ctmModel == ImageParams.CTM_MODEL._8_NEIGHBOR)
                    {
                        //8-邻域
                        double[,] nei = new double[,] {
                                                    { src[y - 1, x - 1].Intensity, src[y-1, x ].Intensity, src[y - 1, x + 1].Intensity },
                                                    { src[y, x - 1].Intensity, src[y, x].Intensity, src[y , x + 1].Intensity },
                                                    { src[y + 1, x - 1].Intensity, src[y + 1, x].Intensity, src[y + 1, x + 1].Intensity },
                                                  };
                        Matrix<double> m = new Matrix<double>(nei);
                        //8-邻域均值
                        double anv8 = m.Sum / 8;

                        template[i] = anv8;
                    }
                    dst.Draw(new CircleF(new PointF(x, y), 2), new Bgr(Color.Green), 2);
                }
                ImageParams.templateGray = template;
            }

            double[] msdList = new double[360];
            for (int deg = 0; deg < 360; deg++)//360可调节
            {
                //转弧度
                double radian = deg * Math.PI / 180;

                double sum = 0;
                for (int i = 0; i < template.Length; i++)
                {
                    int x = (int)(a - i * Math.Cos(radian));
                    int y = (int)(b - i * Math.Sin(radian));
                    x = x <= 0 ? 0 : x;
                    y = y <= 0 ? 0 : y;
                    x = x >= src.Width ? src.Width - 1 : x;
                    y = y >= src.Height ? src.Height - 1 : y;
                    if (ImageParams.ctmModel == ImageParams.CTM_MODEL.POINT)
                    {
                        sum += (src[y, x].Intensity - template[i]) * (src[y, x].Intensity - template[i]);
                    }
                    else if (ImageParams.ctmModel == ImageParams.CTM_MODEL._8_NEIGHBOR)
                    {
                        //8-邻域
                        double[,] nei = new double[,] {
                                                    { src[y - 1, x - 1].Intensity, src[y-1, x ].Intensity, src[y - 1, x + 1].Intensity },
                                                    { src[y, x - 1].Intensity, src[y, x].Intensity, src[y , x + 1].Intensity },
                                                    { src[y + 1, x - 1].Intensity, src[y + 1, x].Intensity, src[y + 1, x + 1].Intensity },
                                                  };
                        Matrix<double> m = new Matrix<double>(nei);
                        //8-邻域均值
                        double anv8 = m.Sum / 8;
                        sum += (anv8 - template[i]) * (anv8 - template[i]);
                    }


                    //dst.Draw(new CircleF(new PointF(x,y), 1), new Bgr(deg,deg,deg), 1);
                }

                msdList[deg] = sum / r;
            }
            int angle2 = Util.getMinValueIndex(msdList, (obj1, obj2) => {
                return obj1 - obj2 > 0 ? 1 : -1;
            });
            XTrace.WriteLine("最大相似指针角度:" + angle2 + ",匹配误差:" + msdList[angle2] + ",相似度:" + (1 - Math.Sqrt(msdList[angle2])));

            int x0 = (int)(a - r * Math.Cos(angle2 * Math.PI / 180));
            int y0 = (int)(b - r * Math.Sin(angle2 * Math.PI / 180));
            Point p = new Point(x0, y0);
            Point center = Point.Round(circle.Center);
            long end = DateTime.Now.Millisecond;
            //XTrace.WriteLine("耗时:" + (end - start) + "ms");
            lines = new LineSegment2D[1];
            lines[0] = new LineSegment2D(center, p);
            dst.Draw(new LineSegment2D(p, center), new Bgr(Color.Red), 2);
            if (contain != null)
            {
                contain.Image = dst.ToBitmap();
            }
            //PointF[] pfs = new PointF[360];
            //for(int i = 0; i < 360; i++)
            //{
            //    pfs[i]=(new PointF(i,(float)msdList[i]));
            //}
            //double max = Util.getMax(msdList, (obj1, obj2) => { return obj1 - obj2 > 0 ? 1 : -1; });
            //DataUtil dataUtil = new DataUtil("angle","msd",360,(int)max);
            //dataUtil.showMin = true;
            //dst = dataUtil.draw(pfs);
            return dst;
        }

        private static void saveToFile(string fn, string str)
        {
            StreamWriter sw = File.CreateText(@"C:\Users\Administrator\Desktop\毕设\数据\" + fn);
            sw.Write(str);  //写入文件中
            sw.Flush();//清理缓冲区
            sw.Close();//关闭文件
        }

        public Image<Bgr, byte> compositePointer(Image<Gray, byte> src, LineSegment2D line1, LineSegment2D line2, PointF center)
        {
            Image<Bgr, byte> dst = src.Convert<Bgr, byte>();
            //求两条指针线段的交点
            PointF p = Util.getIntersection(line1.P1, line1.P2, line2.P1, line2.P2);
            dst.Draw(new LineSegment2D(Point.Round(p), Point.Round(center)), new Bgr(Color.Yellow), 2);

            return dst;
        }


        public Image<Bgr, byte> drawData(Point[] points, string xText, string yText, int maxX = 400, int maxY = 400, bool showMax = false, bool showMin = false)
        {
            int dstWidth = 500;
            int dstHeight = 500;
            int padding = 50;
            Image<Bgr, byte> dst = new Image<Bgr, byte>(dstWidth, dstHeight).Not();
            double ratioX = maxX > 400 ? maxX / 400 : 1;
            double ratioY = maxY > 400 ? maxY / 400 : 1;

            //画坐标轴
            Point O = new Point(padding, 450);
            Point X = new Point(450, 450);
            Point Y = new Point(padding, padding);
            dst.Draw(new LineSegment2D(O, X), new Bgr(Color.Black), 2);
            dst.Draw(new LineSegment2D(O, Y), new Bgr(Color.Black), 2);
            dst.Draw(yText, new Point(5, padding / 2), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
            dst.Draw(xText, new Point(dstWidth - padding * 2, dstHeight - padding / 2), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
            foreach (Point p in points)
            {
                Point pp = new Point((int)(p.X / ratioX + padding), (int)(dstHeight - padding - p.Y / ratioY));
                dst.Draw(new CircleF(pp, 1), new Bgr(Color.Black), 2);
            }
            if (showMax)
            {
                //绘制最大值
                Point maxPoint = Util.getMax(points, (obj1, obj2) =>
                {
                    return obj1.Y - obj2.Y;
                });
                Point maxpp = new Point((int)(maxPoint.X / ratioX + padding), (int)(dstHeight - padding - maxPoint.Y / ratioY));
                dst.Draw(new CircleF(maxpp, 3), new Bgr(Color.Red), 5);
                dst.Draw("(" + maxPoint.X + "," + maxPoint.Y + ")", maxpp, Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
                dst.Draw(new LineSegment2D(new Point(maxpp.X, dstHeight - padding), maxpp), new Bgr(Color.Red), 1);//x
                dst.Draw(new LineSegment2D(new Point(padding, maxpp.Y), maxpp), new Bgr(Color.Red), 1);//y
            }
            if (showMin)
            {
                //绘制最小值
                Point maxPoint = Util.getMax(points, (obj1, obj2) =>
                {
                    return obj2.Y - obj1.Y;
                });
                Point maxpp = new Point((int)(maxPoint.X / ratioX + padding), (int)(dstHeight - padding - maxPoint.Y / ratioY));
                dst.Draw(new CircleF(maxpp, 3), new Bgr(Color.Red), 5);
                dst.Draw("(" + maxPoint.X + "," + maxPoint.Y + ")", maxpp, Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
                dst.Draw(new LineSegment2D(new Point(maxpp.X, dstHeight - padding), maxpp), new Bgr(Color.Red), 1);//x
                dst.Draw(new LineSegment2D(new Point(padding, maxpp.Y), maxpp), new Bgr(Color.Red), 1);//y
            }
            return dst;
        }
        public Image<Bgr, byte> drawData(PointF[] points, string xText, string yText, int maxX = 400, int maxY = 400, bool showMax = false, bool showMin = false, bool showConcentratedArea = false, int concentratedArea = 10)
        {
            int dstWidth = 500;
            int dstHeight = 500;
            int padding = 50;
            Image<Bgr, byte> dst = new Image<Bgr, byte>(dstWidth, dstHeight).Not();
            double ratioX = maxX > 400 ? maxX / 400 : 1;
            double ratioY = maxY > 400 ? maxY / 400 : 1;

            //画坐标轴
            Point O = new Point(padding, 450);
            Point X = new Point(450, 450);
            Point Y = new Point(padding, padding);
            dst.Draw(new LineSegment2D(O, X), new Bgr(Color.Black), 2);
            dst.Draw(new LineSegment2D(O, Y), new Bgr(Color.Black), 2);
            dst.Draw(yText, new Point(5, padding / 2), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
            dst.Draw(xText, new Point(dstWidth - padding * 2, dstHeight - padding / 2), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
            foreach (PointF p in points)
            {
                Point pp = new Point((int)(p.X / ratioX + padding), (int)(dstHeight - padding - p.Y / ratioY));
                dst.Draw(new CircleF(pp, 1), new Bgr(Color.Black), 2);
            }
            if (showMax)
            {
                //绘制最大值
                PointF maxPoint = Util.getMax(points, (obj1, obj2) =>
                {
                    return (int)obj1.Y - (int)obj2.Y;
                });
                Point maxpp = new Point((int)(maxPoint.X / ratioX + padding), (int)(dstHeight - padding - maxPoint.Y / ratioY));
                dst.Draw(new CircleF(maxpp, 3), new Bgr(Color.Red), 5);
                dst.Draw("(" + maxPoint.X + "," + maxPoint.Y + ")", maxpp, Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
                dst.Draw(new LineSegment2D(new Point(maxpp.X, dstHeight - padding), maxpp), new Bgr(Color.Red), 1);//x
                dst.Draw(new LineSegment2D(new Point(padding, maxpp.Y), maxpp), new Bgr(Color.Red), 1);//y
            }
            if (showMin)
            {
                //绘制最小值
                PointF maxPoint = Util.getMax(points, (obj1, obj2) =>
                {
                    return (int)obj1.Y - (int)obj2.Y;
                });
                Point maxpp = new Point((int)(maxPoint.X / ratioX + padding), (int)(dstHeight - padding - maxPoint.Y / ratioY));
                dst.Draw(new CircleF(maxpp, 3), new Bgr(Color.Red), 5);
                dst.Draw("(" + maxPoint.X + "," + maxPoint.Y + ")", maxpp, Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(Color.Black));
                dst.Draw(new LineSegment2D(new Point(maxpp.X, dstHeight - padding), maxpp), new Bgr(Color.Red), 1);//x
                dst.Draw(new LineSegment2D(new Point(padding, maxpp.Y), maxpp), new Bgr(Color.Red), 1);//y
            }

            return dst;
        }
    }
}
